// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1ns/1ns
`default_nettype none
`include "logic.svh"

import i3c_pkg::*;

module i3c_host #(
    parameter PEC_ENABLE_PARAM = 1  // this parameter enables PEC byte support for I3C transmit and receive transfer (for MCTP I3C Binding protocol use-case) 
) (
        //100MHz reference clock to feed into I3c PHY module
        input  wire         clk_100m,
        input  wire         clk_100m_reset_n,
        
        //generated I3c core clock from I3c PHY module with QSYS bridge CDC handling 
        input  wire         clk_i3c, //replace clk_20m with clk_i3c, this will be the generated i3c_core_clk from i3c_phy that went thru QSYS bridge
        input  wire         clk_i3c_reset_n, //replace 20Mhz reset_n (nios clk) with i3c_core_reset that went thru QSYS bridge
        
        input  wire         reset_n, //optional soft reset to the I3c PHY, this will generate a reset to clk_i3c_reset_n
        
        input  wire         avm_read,
        output wire [31:0]  avm_readdata,
        output wire         avm_readdatavalid,
        input  wire         avm_write,
        input  wire [31:0]  avm_writedata,
        input  wire [7:0]   avm_address,
        output wire         avm_waitrequest,

        output wire         pur_oe,
        
        // I3C bus
        input  wire         scl_data_in,    
        output wire         scl_data_out,     
        output wire         scl_oe,

        input  wire         sda_data_in,    
        output wire         sda_data_out,     
        output wire         sda_oe,
        
        output wire         i3c_core_clk,
        output wire         i3c_core_reset_n
);

// ------------------ Configuration signals for I3C PHY ------------------- //
logic       cfg_operation_mode; // Selectable Master/Slave mode : 0 - SLAVE, 1 - MASTER
device_t    cfg_device;         // Selectable I2C/I3C : 0 - I3C, 1 - I2C
logic [2:0] cfg_mode;           // 3'bit Configuring link speed. 
// -------------------------------------------------------------------
// -- PHY clock management 
// -- Interface -- Link Frequency -- Core Clock -- Device --  Mode  --
// -- I3C SDR0  --    12.5MHz     --   100MHz   --  1'b0  -- 3'b000 -- 
// -- I3C SDR1  --     8MHz       --    64MHz   --  1'b0  -- 3'b001 -- 
// -- I3C SDR2  --     6MHz       --    48MHz   --  1'b0  -- 3'b010 -- 
// -- I3C SDR3  --     4MHz       --    32MHz   --  1'b0  -- 3'b011 -- 
// -- I3C SDR4  --     2MHz       --    16MHz   --  1'b1  -- 3'b100 -- 
// -- I2C Fm+   --     1MHz       --     8MHz   --  1'b1  -- 3'b001 -- 
// -- I2C Fm    --    400kHz      --   3.2MHz   --  1'b1  -- 3'b000 -- 
// -- I2C UDR1  --    100kHz      --   800kHz   --  1'b1  -- 3'b010 -- 
// -------------------------------------------------------------------
logic     cfg_speed;          // Fast or slow (400KHz) clock speed : 0 - Fast, 1 - Slow (400KHz)
logic       cfg_busy;           // 1 - busy - not available to change a device, mode & speed parameters
logic [2:0] cfg_error;          // Error codes for dynamic clock configuration.
// -------------------------------------------------------------------
// -- Error Codes
// -- 000 - Non-Error
// -- 001 - I2C Mode not exist
// -- 010 - I3C Mode not exist
// -- 100 - PLL not locked
// -------------------------------------------------------------------


// ------------------ Management signals for I3C PHY ------------------- //
logic       mgmt_busy; //Transaction in progress. not used in master_fsm
status_t    mgmt_status; //data link status. i3c PHY status that moves our master_fsm
request_t   mgmt_request; //data link action request
logic [7:0] mgmt_wr_data; //data for write on expected request
logic [7:0] mgmt_rd_data; //data read from data link
logic       mgmt_rd_data_valid; //new signal in new i3c PHY. data read valid signal for capturing. not yet implemented in master_fsm

logic [7:0] link_speed;
logic [2:0] i3c_speed;
logic [31:0] transaction_status;
logic read_cmd_fifo;

logic bus_enable;
logic resume;
logic abort;
logic [31:0] ibi;
logic ibi_message_ready;
logic ibi_message_clear;
logic command_fifo_read_req;
logic [31:0] command_fifo_read_data;
logic response_fifo_write_req;
logic [31:0] response_fifo_write_data;
logic read_fifo_write_req;
logic [31:0] read_fifo_write_data;
logic write_fifo_read_req;
logic [31:0] write_fifo_read_data;
logic command_fifo_empty;
logic command_fifo_full;
logic response_fifo_empty;
logic response_fifo_full;
logic read_fifo_empty;
logic read_fifo_full;
logic write_fifo_empty;
logic write_fifo_full;
logic clr_read_fifo_dyn_addr_par_pulse;

reg_file_hci u_reg_file_hci (
        .clk(clk_i3c),
        .clk_50m(clk_i3c),
        .reset_n(clk_i3c_reset_n),

        .avm_read(avm_read),
        .avm_readdata(avm_readdata),
        .avm_readdatavalid(avm_readdatavalid),
        .avm_write(avm_write),
        .avm_writedata(avm_writedata),
        .avm_address(avm_address),
        .avm_waitrequest(avm_waitrequest),

        .bus_enable(bus_enable),
        .resume(resume),
        .abort(abort),
        .ibi(ibi),
        .ibi_message_ready(ibi_message_ready),
        .ibi_message_clear(ibi_message_clear),

        .command_fifo_read_req(command_fifo_read_req),
        .command_fifo_read_data(command_fifo_read_data),
        .command_fifo_empty(command_fifo_empty),
        .command_fifo_full(command_fifo_full),
        
        .clr_read_fifo_dyn_addr_par_pulse(clr_read_fifo_dyn_addr_par_pulse),
        
        .response_fifo_write_req(response_fifo_write_req),
        .response_fifo_write_data(response_fifo_write_data),
        .response_fifo_empty(response_fifo_empty),
        .response_fifo_full(response_fifo_full),

        .read_fifo_write_req(read_fifo_write_req),
        .read_fifo_write_data(read_fifo_write_data),
        .read_fifo_empty(read_fifo_empty),
        .read_fifo_full(read_fifo_full),

        .write_fifo_read_req(write_fifo_read_req),
        .write_fifo_read_data(write_fifo_read_data),
        .write_fifo_empty(write_fifo_empty),
        .write_fifo_full(write_fifo_full)
);
master_fsm #(
    .PEC_ENABLE_PARAM   (PEC_ENABLE_PARAM)   
) u_fsm (
        .clk(clk_i3c),
        .reset_n(clk_i3c_reset_n),

        .bus_enable(bus_enable),
        .resume(resume),
        .abort(abort),
        .ibi(ibi),
        .ibi_message_ready(ibi_message_ready),
        .ibi_message_clear(ibi_message_clear),

        .command_fifo_read_req(command_fifo_read_req),
        .command_fifo_read_data(command_fifo_read_data),
        .command_fifo_empty(command_fifo_empty),
        .command_fifo_full(command_fifo_full),
        
        .clr_read_fifo_dyn_addr_par_pulse(clr_read_fifo_dyn_addr_par_pulse),
        
        .response_fifo_write_req(response_fifo_write_req),
        .response_fifo_write_data(response_fifo_write_data),
        .response_fifo_empty(response_fifo_empty),
        .response_fifo_full(response_fifo_full),

        .read_fifo_write_req(read_fifo_write_req),
        .read_fifo_write_data(read_fifo_write_data),
        .read_fifo_empty(read_fifo_empty),
        .read_fifo_full(read_fifo_full),

        .write_fifo_read_req(write_fifo_read_req),
        .write_fifo_read_data(write_fifo_read_data),
        .write_fifo_empty(write_fifo_empty),
        .write_fifo_full(write_fifo_full),

        .busy(mgmt_busy),
        .status(mgmt_status),
        .request(mgmt_request),
        .wr_data(mgmt_wr_data),
        .rd_data(mgmt_rd_data),
        .rd_data_valid(mgmt_rd_data_valid),
        
        .link_speed(link_speed),
        .i3c_speed(i3c_speed)

);

    i3c_phy_cfg_if i3c_phy_cfg_if_inst (
        .clk    (clk_100m),
        .rstn   (clk_100m_reset_n)
    );

    i3c_phy_mgmt_if i3c_phy_mgmt_if_inst (
        .clk    (clk_100m),
        .rstn   (clk_100m_reset_n)
    );
// Configuration signal assignment.
assign cfg_operation_mode = 1'b1; //MASTER mode
assign cfg_device         = device_t'(1'b0); //I3C device
assign cfg_mode           = i3c_speed; 
assign cfg_speed          = 1'b1; //fast mode

assign i3c_phy_cfg_if_inst.operation_mode = operation_mode_t'(1'b1);
assign i3c_phy_cfg_if_inst.device         = device_t'(1'b0); //I3C device 
assign i3c_phy_cfg_if_inst.mode           = i3c_speed;
assign cfg_error                          = i3c_phy_cfg_if_inst.error;

assign mgmt_busy                          = i3c_phy_mgmt_if_inst.busy;
assign mgmt_status                        = i3c_phy_mgmt_if_inst.status;
assign i3c_phy_mgmt_if_inst.request       = mgmt_request;
assign i3c_phy_mgmt_if_inst.wr_data       = mgmt_wr_data;
assign mgmt_rd_data                       = i3c_phy_mgmt_if_inst.rd_data;
assign mgmt_rd_data_valid                 = i3c_phy_mgmt_if_inst.rd_data_valid;

i3c_phy u_phy (
        // Clock interface
        .clk(clk_100m),
        // Logic reset - soft IP reset
        .reset_n(clk_100m_reset_n),
        
        // Configuration signals - currently all hard coded to default values as we are using BYPASS mode in the PHY clk mgmt module
        // Configuration signals
        .cfg(i3c_phy_cfg_if_inst),

        // MGMT signals
        .mgmt(i3c_phy_mgmt_if_inst),  
        // I3C bus signals
        .scl_data_in(scl_data_in),    
        .scl_data_out(scl_data_out),     
        .scl_oe(scl_oe),

        .sda_data_in(sda_data_in),    
        .sda_data_out(sda_data_out),     
        .sda_oe(sda_oe),

        // External Pull-up Resistor enable
        .pur_oe(pur_oe)
);
  assign i3c_core_clk     = clk_100m;
  assign i3c_core_reset_n = clk_100m_reset_n;
endmodule
